/**
 * 上海中赢金融信息服务有限公司
 * Copyright (c) 2017-2027 Chinazyjr,Inc.All Rights Reserved.
 */
package com.sys.midware.hive.handler;

import java.lang.reflect.Field;
import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.ResultSetMetaData;
import java.sql.SQLException;
import java.sql.Statement;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.Iterator;
import java.util.List;
import java.util.Map;

import org.apache.commons.collections.CollectionUtils;

import com.sys.midware.hive.exceptions.BHiveException;
import com.sys.midware.hive.handler.op.DeleteParams;
import com.sys.midware.hive.handler.op.ExecuteParams;
import com.sys.midware.hive.handler.op.InsertParams;
import com.sys.midware.hive.handler.op.QueryParams;
import com.sys.midware.hive.handler.op.UpdateParams;
import com.sys.midware.hive.pool.IConnectionPool;
import com.sys.midware.hive.utils.DBUtil;
import com.sys.midware.logger.Logger;
import com.sys.midware.logger.LoggerFactory;

/**
 * 
 * <b>Description：</b> Hive 处理类 <br/>
 * <b>ClassName：</b> HiveHandler <br/>
 * <b>@author：</b> mobing <br/>
 * <b>@date：</b> 2017年1月24日 下午2:43:35 <br/>
 * <b>@version: </b> <br/>
 */
public class HiveHandler4JDBC implements IHiveHandler {

    private static Logger logger = LoggerFactory.getLogger(HiveHandler4JDBC.class);

    public HiveHandler4JDBC() {

    }
    
    private IConnectionPool pool;
    
    public HiveHandler4JDBC(IConnectionPool pool) {
        this.pool = pool;
    }
    

    public  <E> List<Map<String, Object>> queryMapList(QueryParams queryParams) {
        if (queryParams == null || queryParams.getQueryStr() == null)
            throw new BHiveException("the query string is null!");

        String sql = queryParams.getQueryStr();
        List<?> params = queryParams.getParams();
        List<Map<String, Object>> lists = new ArrayList<Map<String, Object>>();
        Connection connection =null;
        PreparedStatement pstmt = null;
        ResultSet rs = null;
        Statement stmt = null;
        try {
            connection = this.pool.getConnection();
            if (params == null || params.size() == 0) {
                stmt = connection.createStatement();
                rs = stmt.executeQuery(sql);
            } else {
                pstmt = connection.prepareStatement(sql);
                // 设置参数
                for (int i = 0; i < params.size(); i++) {
                    Object o = params.get(i);
                    pstmt.setObject((i + 1), o);
                }
                rs = pstmt.executeQuery();
            }
            if (rs != null) {
                ResultSetMetaData rsmd = rs.getMetaData();
                int columnCount = rsmd.getColumnCount();
                while (null != rs && rs.next()) {
                    Map<String, Object> map = new HashMap<String, Object>();
                    for (int i = 0; i < columnCount; i++) {
                        String name = rsmd.getColumnName(i + 1);
                        Object value = rs.getObject(name);
                        map.put(name, value);
                    }
                    lists.add(map);
                }
            }
        } catch (Exception e) {
            logger.error("fail to queryMapList!",e);
        } finally {
            this.pool.releaseConnection(connection);
        }
        return lists;
    }

    @Override
    public <T, E> List<T> queryBeanList(QueryParams queryParams, Class<T> beanClass) {
        if (queryParams == null || queryParams.getQueryStr() == null)
            throw new BHiveException("the query string is null!");

        String sql = queryParams.getQueryStr();
        List<?> params = queryParams.getParams();
        List<T> lists = new ArrayList<T>();
        Connection connection = null;
        PreparedStatement pstmt = null;
        ResultSet rs = null;
        Statement stmt = null;
        try {
            connection = this.pool.getConnection();
            if (params == null || params.size() == 0) {
                stmt = connection.createStatement();
                rs = stmt.executeQuery(sql);
            } else {
                pstmt = connection.prepareStatement(sql);
                // 设置参数
                for (int i = 0; i < params.size(); i++) {
                    Object o = params.get(i);
                    pstmt.setObject((i + 1), o);
                }
                rs = pstmt.executeQuery();
            }
            if (rs != null) {
                Field[] fields = null;
                fields = beanClass.getDeclaredFields();
                for (Field f : fields){
                    f.setAccessible(true);
                }
                while (null != rs && rs.next()) {
                    T t = beanClass.newInstance();
                    for (Field f : fields) {
                        String name = f.getName();
                        try {
                            Object value = rs.getObject(name);
                            DBUtil.setValue(t, f, value);
                        } catch (Exception e) {
                        }
                    }
                    lists.add(t);
                }
            }
        } catch (Exception e) {
            logger.error(e);
        } finally {
            this.pool.releaseConnection(connection);
        }
        return lists;
    }

    public void performInsert(InsertParams<?> ip)  {
        Connection connection = null;
        PreparedStatement pstmt = null;
        try {
            connection = this.pool.getConnection();
            Map<String, ?> params = ip.getParams();
            ArrayList<Object> paramArray = new ArrayList<Object>();
            StringBuffer bf = new StringBuffer();
            bf.append("INSERT INTO ");
            bf.append(ip.getTableName());
            bf.append(" (");
            StringBuilder values = new StringBuilder(" VALUES (");

            // loop for cols
            Iterator it = params.entrySet().iterator();
            boolean first = true;
            while (it.hasNext()) {
                Map.Entry e = (Map.Entry) it.next();
                String key = (String) e.getKey();

                Object o = e.getValue();
                if (o != null) {
                    paramArray.add(o);

                    if (!first) {
                        bf.append(',');
                        values.append(',');
                    }
                    bf.append(key);
                    values.append('?');

                    first = false;
                }
            }

            bf.append(')');
            values.append(')');
            bf.append(values);

            pstmt = connection.prepareStatement(bf.toString());
            if (paramArray.size() > 0) {
                int idx = 1;
                for (Object o : paramArray) {
                    pstmt.setObject(idx, o);
                    idx++;
                }
            }

            pstmt.execute();
        } catch (Exception e) {
            throw new BHiveException("performInsert error!", e);
        } finally {
            this.pool.releaseConnection(connection);
        }
    }

    public void performInsertBatch(List<InsertParams<?>> records)  {
        Connection connection = null;
        try {
            connection = this.pool.getConnection();
            boolean oldAutoCommitMode = connection.getAutoCommit();// 保存原来的自动提交模式
            connection.setAutoCommit(false);// 不要自动提交

            for (int i = 0; i < records.size(); i++) {
                this.performInsert(records.get(i));
            }
            connection.commit();// 手动触发提交
            connection.setAutoCommit(oldAutoCommitMode);// 恢复原来的自动提交模式
        } catch (Exception e) {
            throw new BHiveException("performInsertBatch error!", e);
        } finally {
            this.pool.releaseConnection(connection);
        }
    }

    public void performUpdate(UpdateParams<?, ?> up) throws BHiveException {
        // UpdateParams<?, ?> up = (UpdateParams<?, ?>) record;
        String tableName = up.getTableName();
        Map<String, ?> fields = up.getUpdateFields();

        if (tableName == null || fields == null || fields.size() == 0)
            throw new BHiveException("Invalid SQL statement for postgresql update!");
        Connection connection = null;
        PreparedStatement pstmt = null;
        try {
            connection = this.pool.getConnection();
            String whereClause = up.getWhereClause();
            List<?> whereParams = up.getWhereParams();

            List<Object> paramArray = new ArrayList<Object>();
            StringBuilder sb = new StringBuilder("update ");
            sb.append(tableName).append(" set ");

            Iterator it = fields.entrySet().iterator();
            boolean first = true;
            while (it.hasNext()) {
                Map.Entry e = (Map.Entry) it.next();
                String key = (String) e.getKey();

                Object o = e.getValue();

                if (!first) {
                    sb.append(',');
                }
                sb.append(key);
                sb.append('=');
                if (o == null) {
                    sb.append("NULL");
                } else {
                    sb.append('?');
                    paramArray.add(o);
                }

                first = false;
            }

            if (whereClause != null) {
                sb.append(' ');
                sb.append(whereClause);
                if (whereParams != null) {
                    for (int j = 0; j < whereParams.size(); j++) {
                        Object value = whereParams.get(j);
                        paramArray.add(value);
                    }
                }
            }
            pstmt = connection.prepareStatement(sb.toString());
            setParametersIntoPreparedStatement(paramArray, pstmt);
            pstmt.execute();
        } catch (Exception e) {
//            throw new BHiveException("performUpdate error!", e);
        } finally {
            this.pool.releaseConnection(connection);
        }

    }

    public void performUpdateBatch(List<UpdateParams<?, ?>> records) throws BHiveException {
        for (int i = 0; i < records.size(); i++) {
            this.performUpdate(records.get(i));
        }
    }

    public void performDeleteBatch(List<DeleteParams<?>> records) throws BHiveException {
        for (int i = 0; i < records.size(); i++){
            this.performDelete(records.get(i));
        }
    }

    public void performDelete(DeleteParams<?> record) throws BHiveException {
        DeleteParams<?> dp = (DeleteParams<?>) record;
        String tableName = dp.getTableName();
        String whereClause = dp.getWhereClause();
        List<?> whereParams = dp.getWhereParams();
        Connection connection = null;
        PreparedStatement pstmt = null;
        Statement stmt = null;
        try {
            connection = this.pool.getConnection();
            StringBuilder sb = new StringBuilder("delete from ");
            sb.append(tableName);
            if (whereClause != null) {
                sb.append(" ").append(whereClause);
                pstmt = connection.prepareStatement(sb.toString());
                for (int j = 0; j < whereParams.size(); j++) {
                    pstmt.setObject((j + 1), whereParams.get(j));
                }
                stmt = pstmt;
                pstmt.execute();
            } else {
                stmt = connection.createStatement();
                stmt.execute(sb.toString());
            }

        } catch (Exception e) {
            throw new BHiveException("performDelete error!", e);
        } finally {
            this.pool.releaseConnection(connection);
        }

    }

    private void setParametersIntoPreparedStatement(List<Object> paramArray, PreparedStatement ps) throws SQLException {
        if (CollectionUtils.isEmpty(paramArray) || ps == null) {
            return;
        }

        int parameterIndex = 0;
        for (Object param : paramArray) {
            Class<? extends Object> paramClass = param.getClass();
            if (paramClass.equals(Integer.class)) {
                ps.setInt(++parameterIndex, (Integer) param);
            } else if (paramClass.equals(Long.class)) {
                ps.setLong(++parameterIndex, (Long) param);
            } else if (paramClass.equals(String.class)) {
                ps.setString(++parameterIndex, (String) param);
            } else if (paramClass.equals(Boolean.class)) {
                ps.setBoolean(++parameterIndex, (Boolean) param);
            } else {
                ps.setObject(++parameterIndex, param);
            }
        }
    }

   
    
    @Override
    public boolean execute(ExecuteParams executeParams) {
        if (executeParams == null || executeParams.getSql() == null)
            throw new BHiveException("the sql  is null!");
        boolean flag=false;
        String sql = executeParams.getSql();
        List<?> params = executeParams.getParams();
        Connection connection = null;
        PreparedStatement pstmt = null;
//        ResultSet rs = null;
        Statement stmt = null;
        try {
            connection = this.pool.getConnection();
            if (params == null || params.size() == 0) {
                stmt = connection.createStatement();
                 stmt.execute(sql);
            } else {
                pstmt = connection.prepareStatement(sql);
                // 设置参数
                for (int i = 0; i < params.size(); i++) {
                    Object o = params.get(i);
                    pstmt.setObject((i + 1), o);
                }
               pstmt.execute(sql);
            }
            flag=true;
        } catch (Exception e) {
            flag=false;
            logger.error(e);
            throw new BHiveException(e);
        } finally {
//            close(stmt, pstmt, connection);
            this.pool.releaseConnection(connection);
        }
        return  flag;
    }

}
